/**
 * Copyright (c) Tiny Technologies, Inc. All rights reserved.
 * Licensed under the LGPL or a commercial license.
 * For LGPL see License.txt in the project root for license information.
 * For commercial licenses see https://www.tiny.cloud/
 *
 * Version: 5.10.0 (2021-10-11)
 */
(function() {
  'use strict'

  var Cell = function(initial) {
    var value = initial
    var get = function() {
      return value
    }
    var set = function(v) {
      value = v
    }
    return {
      get: get,
      set: set
    }
  }

  var global$3 = tinymce.util.Tools.resolve('tinymce.PluginManager')

  var __assign = function() {
    __assign = Object.assign || function __assign(t) {
      for (var s, i = 1, n = arguments.length;i < n;i++) {
        s = arguments[i]
        for (var p in s) {
          if (Object.prototype.hasOwnProperty.call(s, p)) { t[p] = s[p] }
        }
      }
      return t
    }
    return __assign.apply(this, arguments)
  }

  var typeOf = function(x) {
    var t = typeof x
    if (x === null) {
      return 'null'
    } else if (t === 'object' && (Array.prototype.isPrototypeOf(x) || x.constructor && x.constructor.name === 'Array')) {
      return 'array'
    } else if (t === 'object' && (String.prototype.isPrototypeOf(x) || x.constructor && x.constructor.name === 'String')) {
      return 'string'
    } else {
      return t
    }
  }
  var isType$1 = function(type) {
    return function(value) {
      return typeOf(value) === type
    }
  }
  var isSimpleType = function(type) {
    return function(value) {
      return typeof value === type
    }
  }
  var isString = isType$1('string')
  var isArray = isType$1('array')
  var isBoolean = isSimpleType('boolean')
  var isNumber = isSimpleType('number')

  var noop = function() {
  }
  var constant = function(value) {
    return function() {
      return value
    }
  }
  var identity = function(x) {
    return x
  }
  var never = constant(false)
  var always = constant(true)

  var punctuationStr = '[!-#%-*,-\\/:;?@\\[-\\]_{}\xA1\xAB\xB7\xBB\xBF;\xB7\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1361-\u1368\u1400\u166D\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205E\u207D\u207E\u208D\u208E\u3008\u3009\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30\u2E31\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uff3f\uFF5B\uFF5D\uFF5F-\uFF65]'

  var punctuation$1 = constant(punctuationStr)

  var none = function() {
    return NONE
  }
  var NONE = (function() {
    var call = function(thunk) {
      return thunk()
    }
    var id = identity
    var me = {
      fold: function(n, _s) {
        return n()
      },
      isSome: never,
      isNone: always,
      getOr: id,
      getOrThunk: call,
      getOrDie: function(msg) {
        throw new Error(msg || 'error: getOrDie called on none.')
      },
      getOrNull: constant(null),
      getOrUndefined: constant(undefined),
      or: id,
      orThunk: call,
      map: none,
      each: noop,
      bind: none,
      exists: never,
      forall: always,
      filter: function() {
        return none()
      },
      toArray: function() {
        return []
      },
      toString: constant('none()')
    }
    return me
  }())
  var some = function(a) {
    var constant_a = constant(a)
    var self = function() {
      return me
    }
    var bind = function(f) {
      return f(a)
    }
    var me = {
      fold: function(n, s) {
        return s(a)
      },
      isSome: always,
      isNone: never,
      getOr: constant_a,
      getOrThunk: constant_a,
      getOrDie: constant_a,
      getOrNull: constant_a,
      getOrUndefined: constant_a,
      or: self,
      orThunk: self,
      map: function(f) {
        return some(f(a))
      },
      each: function(f) {
        f(a)
      },
      bind: bind,
      exists: bind,
      forall: bind,
      filter: function(f) {
        return f(a) ? me : NONE
      },
      toArray: function() {
        return [a]
      },
      toString: function() {
        return 'some(' + a + ')'
      }
    }
    return me
  }
  var from = function(value) {
    return value === null || value === undefined ? NONE : some(value)
  }
  var Optional = {
    some: some,
    none: none,
    from: from
  }

  var punctuation = punctuation$1

  var global$2 = tinymce.util.Tools.resolve('tinymce.util.Tools')

  var nativeSlice = Array.prototype.slice
  var nativePush = Array.prototype.push
  var map = function(xs, f) {
    var len = xs.length
    var r = new Array(len)
    for (var i = 0;i < len;i++) {
      var x = xs[i]
      r[i] = f(x, i)
    }
    return r
  }
  var each = function(xs, f) {
    for (var i = 0, len = xs.length;i < len;i++) {
      var x = xs[i]
      f(x, i)
    }
  }
  var eachr = function(xs, f) {
    for (var i = xs.length - 1;i >= 0;i--) {
      var x = xs[i]
      f(x, i)
    }
  }
  var groupBy = function(xs, f) {
    if (xs.length === 0) {
      return []
    } else {
      var wasType = f(xs[0])
      var r = []
      var group = []
      for (var i = 0, len = xs.length;i < len;i++) {
        var x = xs[i]
        var type = f(x)
        if (type !== wasType) {
          r.push(group)
          group = []
        }
        wasType = type
        group.push(x)
      }
      if (group.length !== 0) {
        r.push(group)
      }
      return r
    }
  }
  var foldl = function(xs, f, acc) {
    each(xs, function(x, i) {
      acc = f(acc, x, i)
    })
    return acc
  }
  var flatten = function(xs) {
    var r = []
    for (var i = 0, len = xs.length;i < len;++i) {
      if (!isArray(xs[i])) {
        throw new Error('Arr.flatten item ' + i + ' was not an array, input: ' + xs)
      }
      nativePush.apply(r, xs[i])
    }
    return r
  }
  var bind = function(xs, f) {
    return flatten(map(xs, f))
  }
  var sort = function(xs, comparator) {
    var copy = nativeSlice.call(xs, 0)
    copy.sort(comparator)
    return copy
  }

  var hasOwnProperty = Object.hasOwnProperty
  var has = function(obj, key) {
    return hasOwnProperty.call(obj, key)
  }

  typeof window !== 'undefined' ? window : Function('return this;')()

  var DOCUMENT = 9
  var DOCUMENT_FRAGMENT = 11
  var ELEMENT = 1
  var TEXT = 3

  var type = function(element) {
    return element.dom.nodeType
  }
  var isType = function(t) {
    return function(element) {
      return type(element) === t
    }
  }
  var isText$1 = isType(TEXT)

  var rawSet = function(dom, key, value) {
    if (isString(value) || isBoolean(value) || isNumber(value)) {
      dom.setAttribute(key, value + '')
    } else {
      console.error('Invalid call to Attribute.set. Key ', key, ':: Value ', value, ':: Element ', dom)
      throw new Error('Attribute value was not simple')
    }
  }
  var set = function(element, key, value) {
    rawSet(element.dom, key, value)
  }

  var compareDocumentPosition = function(a, b, match) {
    return (a.compareDocumentPosition(b) & match) !== 0
  }
  var documentPositionPreceding = function(a, b) {
    return compareDocumentPosition(a, b, Node.DOCUMENT_POSITION_PRECEDING)
  }

  var fromHtml = function(html, scope) {
    var doc = scope || document
    var div = doc.createElement('div')
    div.innerHTML = html
    if (!div.hasChildNodes() || div.childNodes.length > 1) {
      console.error('HTML does not have a single root node', html)
      throw new Error('HTML must have a single root node')
    }
    return fromDom(div.childNodes[0])
  }
  var fromTag = function(tag, scope) {
    var doc = scope || document
    var node = doc.createElement(tag)
    return fromDom(node)
  }
  var fromText = function(text, scope) {
    var doc = scope || document
    var node = doc.createTextNode(text)
    return fromDom(node)
  }
  var fromDom = function(node) {
    if (node === null || node === undefined) {
      throw new Error('Node cannot be null or undefined')
    }
    return { dom: node }
  }
  var fromPoint = function(docElm, x, y) {
    return Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom)
  }
  var SugarElement = {
    fromHtml: fromHtml,
    fromTag: fromTag,
    fromText: fromText,
    fromDom: fromDom,
    fromPoint: fromPoint
  }

  var bypassSelector = function(dom) {
    return dom.nodeType !== ELEMENT && dom.nodeType !== DOCUMENT && dom.nodeType !== DOCUMENT_FRAGMENT || dom.childElementCount === 0
  }
  var all = function(selector, scope) {
    var base = scope === undefined ? document : scope.dom
    return bypassSelector(base) ? [] : map(base.querySelectorAll(selector), SugarElement.fromDom)
  }

  var parent = function(element) {
    return Optional.from(element.dom.parentNode).map(SugarElement.fromDom)
  }
  var children = function(element) {
    return map(element.dom.childNodes, SugarElement.fromDom)
  }
  var spot = function(element, offset) {
    return {
      element: element,
      offset: offset
    }
  }
  var leaf = function(element, offset) {
    var cs = children(element)
    return cs.length > 0 && offset < cs.length ? spot(cs[offset], 0) : spot(element, offset)
  }

  var before = function(marker, element) {
    var parent$1 = parent(marker)
    parent$1.each(function(v) {
      v.dom.insertBefore(element.dom, marker.dom)
    })
  }
  var append = function(parent, element) {
    parent.dom.appendChild(element.dom)
  }
  var wrap = function(element, wrapper) {
    before(element, wrapper)
    append(wrapper, element)
  }

  var NodeValue = function(is, name) {
    var get = function(element) {
      if (!is(element)) {
        throw new Error('Can only get ' + name + ' value of a ' + name + ' node')
      }
      return getOption(element).getOr('')
    }
    var getOption = function(element) {
      return is(element) ? Optional.from(element.dom.nodeValue) : Optional.none()
    }
    var set = function(element, value) {
      if (!is(element)) {
        throw new Error('Can only set raw ' + name + ' value of a ' + name + ' node')
      }
      element.dom.nodeValue = value
    }
    return {
      get: get,
      getOption: getOption,
      set: set
    }
  }

  var api = NodeValue(isText$1, 'text')
  var get$1 = function(element) {
    return api.get(element)
  }

  var descendants = function(scope, selector) {
    return all(selector, scope)
  }

  var global$1 = tinymce.util.Tools.resolve('tinymce.dom.TreeWalker')

  var isSimpleBoundary = function(dom, node) {
    return dom.isBlock(node) || has(dom.schema.getShortEndedElements(), node.nodeName)
  }
  var isContentEditableFalse = function(dom, node) {
    return dom.getContentEditable(node) === 'false'
  }
  var isContentEditableTrueInCef = function(dom, node) {
    return dom.getContentEditable(node) === 'true' && dom.getContentEditableParent(node.parentNode) === 'false'
  }
  var isHidden = function(dom, node) {
    return !dom.isBlock(node) && has(dom.schema.getWhiteSpaceElements(), node.nodeName)
  }
  var isBoundary = function(dom, node) {
    return isSimpleBoundary(dom, node) || isContentEditableFalse(dom, node) || isHidden(dom, node) || isContentEditableTrueInCef(dom, node)
  }
  var isText = function(node) {
    return node.nodeType === 3
  }
  var nuSection = function() {
    return {
      sOffset: 0,
      fOffset: 0,
      elements: []
    }
  }
  var toLeaf = function(node, offset) {
    return leaf(SugarElement.fromDom(node), offset)
  }
  var walk = function(dom, walkerFn, startNode, callbacks, endNode, skipStart) {
    if (skipStart === void 0) {
      skipStart = true
    }
    var next = skipStart ? walkerFn(false) : startNode
    while (next) {
      var isCefNode = isContentEditableFalse(dom, next)
      if (isCefNode || isHidden(dom, next)) {
        var stopWalking = isCefNode ? callbacks.cef(next) : callbacks.boundary(next)
        if (stopWalking) {
          break
        } else {
          next = walkerFn(true)
          continue
        }
      } else if (isSimpleBoundary(dom, next)) {
        if (callbacks.boundary(next)) {
          break
        }
      } else if (isText(next)) {
        callbacks.text(next)
      }
      if (next === endNode) {
        break
      } else {
        next = walkerFn(false)
      }
    }
  }
  var collectTextToBoundary = function(dom, section, node, rootNode, forwards) {
    if (isBoundary(dom, node)) {
      return
    }
    var rootBlock = dom.getParent(rootNode, dom.isBlock)
    var walker = new global$1(node, rootBlock)
    var walkerFn = forwards ? walker.next.bind(walker) : walker.prev.bind(walker)
    walk(dom, walkerFn, node, {
      boundary: always,
      cef: always,
      text: function(next) {
        if (forwards) {
          section.fOffset += next.length
        } else {
          section.sOffset += next.length
        }
        section.elements.push(SugarElement.fromDom(next))
      }
    })
  }
  var collect = function(dom, rootNode, startNode, endNode, callbacks, skipStart) {
    if (skipStart === void 0) {
      skipStart = true
    }
    var walker = new global$1(startNode, rootNode)
    var sections = []
    var current = nuSection()
    collectTextToBoundary(dom, current, startNode, rootNode, false)
    var finishSection = function() {
      if (current.elements.length > 0) {
        sections.push(current)
        current = nuSection()
      }
      return false
    }
    walk(dom, walker.next.bind(walker), startNode, {
      boundary: finishSection,
      cef: function(node) {
        finishSection()
        if (callbacks) {
          sections.push.apply(sections, callbacks.cef(node))
        }
        return false
      },
      text: function(next) {
        current.elements.push(SugarElement.fromDom(next))
        if (callbacks) {
          callbacks.text(next, current)
        }
      }
    }, endNode, skipStart)
    if (endNode) {
      collectTextToBoundary(dom, current, endNode, rootNode, true)
    }
    finishSection()
    return sections
  }
  var collectRangeSections = function(dom, rng) {
    var start = toLeaf(rng.startContainer, rng.startOffset)
    var startNode = start.element.dom
    var end = toLeaf(rng.endContainer, rng.endOffset)
    var endNode = end.element.dom
    return collect(dom, rng.commonAncestorContainer, startNode, endNode, {
      text: function(node, section) {
        if (node === endNode) {
          section.fOffset += node.length - end.offset
        } else if (node === startNode) {
          section.sOffset += start.offset
        }
      },
      cef: function(node) {
        var sections = bind(descendants(SugarElement.fromDom(node), '*[contenteditable=true]'), function(e) {
          var ceTrueNode = e.dom
          return collect(dom, ceTrueNode, ceTrueNode)
        })
        return sort(sections, function(a, b) {
          return documentPositionPreceding(a.elements[0].dom, b.elements[0].dom) ? 1 : -1
        })
      }
    }, false)
  }
  var fromRng = function(dom, rng) {
    return rng.collapsed ? [] : collectRangeSections(dom, rng)
  }
  var fromNode = function(dom, node) {
    var rng = dom.createRng()
    rng.selectNode(node)
    return fromRng(dom, rng)
  }
  var fromNodes = function(dom, nodes) {
    return bind(nodes, function(node) {
      return fromNode(dom, node)
    })
  }

  var find$2 = function(text, pattern, start, finish) {
    if (start === void 0) {
      start = 0
    }
    if (finish === void 0) {
      finish = text.length
    }
    var regex = pattern.regex
    regex.lastIndex = start
    var results = []
    var match
    while (match = regex.exec(text)) {
      var matchedText = match[pattern.matchIndex]
      var matchStart = match.index + match[0].indexOf(matchedText)
      var matchFinish = matchStart + matchedText.length
      if (matchFinish > finish) {
        break
      }
      results.push({
        start: matchStart,
        finish: matchFinish
      })
      regex.lastIndex = matchFinish
    }
    return results
  }
  var extract = function(elements, matches) {
    var nodePositions = foldl(elements, function(acc, element) {
      var content = get$1(element)
      var start = acc.last
      var finish = start + content.length
      var positions = bind(matches, function(match, matchIdx) {
        if (match.start < finish && match.finish > start) {
          return [{
            element: element,
            start: Math.max(start, match.start) - start,
            finish: Math.min(finish, match.finish) - start,
            matchId: matchIdx
          }]
        } else {
          return []
        }
      })
      return {
        results: acc.results.concat(positions),
        last: finish
      }
    }, {
      results: [],
      last: 0
    }).results
    return groupBy(nodePositions, function(position) {
      return position.matchId
    })
  }

  var find$1 = function(pattern, sections) {
    return bind(sections, function(section) {
      var elements = section.elements
      var content = map(elements, get$1).join('')
      var positions = find$2(content, pattern, section.sOffset, content.length - section.fOffset)
      return extract(elements, positions)
    })
  }
  var mark = function(matches, replacementNode) {
    eachr(matches, function(match, idx) {
      eachr(match, function(pos) {
        var wrapper = SugarElement.fromDom(replacementNode.cloneNode(false))
        set(wrapper, 'data-mce-index', idx)
        var textNode = pos.element.dom
        if (textNode.length === pos.finish && pos.start === 0) {
          wrap(pos.element, wrapper)
        } else {
          if (textNode.length !== pos.finish) {
            textNode.splitText(pos.finish)
          }
          var matchNode = textNode.splitText(pos.start)
          wrap(SugarElement.fromDom(matchNode), wrapper)
        }
      })
    })
  }
  var findAndMark = function(dom, pattern, node, replacementNode) {
    var textSections = fromNode(dom, node)
    var matches = find$1(pattern, textSections)
    mark(matches, replacementNode)
    return matches.length
  }
  var findAndMarkInSelection = function(dom, pattern, selection, replacementNode) {
    var bookmark = selection.getBookmark()
    var nodes = dom.select('td[data-mce-selected],th[data-mce-selected]')
    var textSections = nodes.length > 0 ? fromNodes(dom, nodes) : fromRng(dom, selection.getRng())
    var matches = find$1(pattern, textSections)
    mark(matches, replacementNode)
    selection.moveToBookmark(bookmark)
    return matches.length
  }

  var getElmIndex = function(elm) {
    var value = elm.getAttribute('data-mce-index')
    if (typeof value === 'number') {
      return '' + value
    }
    return value
  }
  var markAllMatches = function(editor, currentSearchState, pattern, inSelection) {
    var marker = editor.dom.create('span', { 'data-mce-bogus': 1 })
    marker.className = 'mce-match-marker'
    var node = editor.getBody()
    done(editor, currentSearchState, false)
    if (inSelection) {
      return findAndMarkInSelection(editor.dom, pattern, editor.selection, marker)
    } else {
      return findAndMark(editor.dom, pattern, node, marker)
    }
  }
  var unwrap = function(node) {
    var parentNode = node.parentNode
    if (node.firstChild) {
      parentNode.insertBefore(node.firstChild, node)
    }
    node.parentNode.removeChild(node)
  }
  var findSpansByIndex = function(editor, index) {
    var spans = []
    var nodes = global$2.toArray(editor.getBody().getElementsByTagName('span'))
    if (nodes.length) {
      for (var i = 0;i < nodes.length;i++) {
        var nodeIndex = getElmIndex(nodes[i])
        if (nodeIndex === null || !nodeIndex.length) {
          continue
        }
        if (nodeIndex === index.toString()) {
          spans.push(nodes[i])
        }
      }
    }
    return spans
  }
  var moveSelection = function(editor, currentSearchState, forward) {
    var searchState = currentSearchState.get()
    var testIndex = searchState.index
    var dom = editor.dom
    forward = forward !== false
    if (forward) {
      if (testIndex + 1 === searchState.count) {
        testIndex = 0
      } else {
        testIndex++
      }
    } else {
      if (testIndex - 1 === -1) {
        testIndex = searchState.count - 1
      } else {
        testIndex--
      }
    }
    dom.removeClass(findSpansByIndex(editor, searchState.index), 'mce-match-marker-selected')
    var spans = findSpansByIndex(editor, testIndex)
    if (spans.length) {
      dom.addClass(findSpansByIndex(editor, testIndex), 'mce-match-marker-selected')
      editor.selection.scrollIntoView(spans[0])
      return testIndex
    }
    return -1
  }
  var removeNode = function(dom, node) {
    var parent = node.parentNode
    dom.remove(node)
    if (dom.isEmpty(parent)) {
      dom.remove(parent)
    }
  }
  var escapeSearchText = function(text, wholeWord) {
    var escapedText = text.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&').replace(/\s/g, '[^\\S\\r\\n\\uFEFF]')
    var wordRegex = '(' + escapedText + ')'
    return wholeWord ? '(?:^|\\s|' + punctuation() + ')' + wordRegex + ('(?=$|\\s|' + punctuation() + ')') : wordRegex
  }
  var find = function(editor, currentSearchState, text, matchCase, wholeWord, inSelection) {
    var escapedText = escapeSearchText(text, wholeWord)
    var pattern = {
      regex: new RegExp(escapedText, matchCase ? 'g' : 'gi'),
      matchIndex: 1
    }
    var count = markAllMatches(editor, currentSearchState, pattern, inSelection)
    if (count) {
      var newIndex = moveSelection(editor, currentSearchState, true)
      currentSearchState.set({
        index: newIndex,
        count: count,
        text: text,
        matchCase: matchCase,
        wholeWord: wholeWord,
        inSelection: inSelection
      })
    }
    return count
  }
  var next = function(editor, currentSearchState) {
    var index = moveSelection(editor, currentSearchState, true)
    currentSearchState.set(__assign(__assign({}, currentSearchState.get()), { index: index }))
  }
  var prev = function(editor, currentSearchState) {
    var index = moveSelection(editor, currentSearchState, false)
    currentSearchState.set(__assign(__assign({}, currentSearchState.get()), { index: index }))
  }
  var isMatchSpan = function(node) {
    var matchIndex = getElmIndex(node)
    return matchIndex !== null && matchIndex.length > 0
  }
  var replace = function(editor, currentSearchState, text, forward, all) {
    var searchState = currentSearchState.get()
    var currentIndex = searchState.index
    var currentMatchIndex;var nextIndex = currentIndex
    forward = forward !== false
    var node = editor.getBody()
    var nodes = global$2.grep(global$2.toArray(node.getElementsByTagName('span')), isMatchSpan)
    for (var i = 0;i < nodes.length;i++) {
      var nodeIndex = getElmIndex(nodes[i])
      var matchIndex = currentMatchIndex = parseInt(nodeIndex, 10)
      if (all || matchIndex === searchState.index) {
        if (text.length) {
          nodes[i].firstChild.nodeValue = text
          unwrap(nodes[i])
        } else {
          removeNode(editor.dom, nodes[i])
        }
        while (nodes[++i]) {
          matchIndex = parseInt(getElmIndex(nodes[i]), 10)
          if (matchIndex === currentMatchIndex) {
            removeNode(editor.dom, nodes[i])
          } else {
            i--
            break
          }
        }
        if (forward) {
          nextIndex--
        }
      } else if (currentMatchIndex > currentIndex) {
        nodes[i].setAttribute('data-mce-index', String(currentMatchIndex - 1))
      }
    }
    currentSearchState.set(__assign(__assign({}, searchState), {
      count: all ? 0 : searchState.count - 1,
      index: nextIndex
    }))
    if (forward) {
      next(editor, currentSearchState)
    } else {
      prev(editor, currentSearchState)
    }
    return !all && currentSearchState.get().count > 0
  }
  var done = function(editor, currentSearchState, keepEditorSelection) {
    var startContainer, endContainer
    var searchState = currentSearchState.get()
    var nodes = global$2.toArray(editor.getBody().getElementsByTagName('span'))
    for (var i = 0;i < nodes.length;i++) {
      var nodeIndex = getElmIndex(nodes[i])
      if (nodeIndex !== null && nodeIndex.length) {
        if (nodeIndex === searchState.index.toString()) {
          if (!startContainer) {
            startContainer = nodes[i].firstChild
          }
          endContainer = nodes[i].firstChild
        }
        unwrap(nodes[i])
      }
    }
    currentSearchState.set(__assign(__assign({}, searchState), {
      index: -1,
      count: 0,
      text: ''
    }))
    if (startContainer && endContainer) {
      var rng = editor.dom.createRng()
      rng.setStart(startContainer, 0)
      rng.setEnd(endContainer, endContainer.data.length)
      if (keepEditorSelection !== false) {
        editor.selection.setRng(rng)
      }
      return rng
    }
  }
  var hasNext = function(editor, currentSearchState) {
    return currentSearchState.get().count > 1
  }
  var hasPrev = function(editor, currentSearchState) {
    return currentSearchState.get().count > 1
  }

  var get = function(editor, currentState) {
    var done$1 = function(keepEditorSelection) {
      return done(editor, currentState, keepEditorSelection)
    }
    var find$1 = function(text, matchCase, wholeWord, inSelection) {
      if (inSelection === void 0) {
        inSelection = false
      }
      return find(editor, currentState, text, matchCase, wholeWord, inSelection)
    }
    var next$1 = function() {
      return next(editor, currentState)
    }
    var prev$1 = function() {
      return prev(editor, currentState)
    }
    var replace$1 = function(text, forward, all) {
      return replace(editor, currentState, text, forward, all)
    }
    return {
      done: done$1,
      find: find$1,
      next: next$1,
      prev: prev$1,
      replace: replace$1
    }
  }

  var singleton = function(doRevoke) {
    var subject = Cell(Optional.none())
    var revoke = function() {
      return subject.get().each(doRevoke)
    }
    var clear = function() {
      revoke()
      subject.set(Optional.none())
    }
    var isSet = function() {
      return subject.get().isSome()
    }
    var get = function() {
      return subject.get()
    }
    var set = function(s) {
      revoke()
      subject.set(Optional.some(s))
    }
    return {
      clear: clear,
      isSet: isSet,
      get: get,
      set: set
    }
  }
  var value = function() {
    var subject = singleton(noop)
    var on = function(f) {
      return subject.get().each(f)
    }
    return __assign(__assign({}, subject), { on: on })
  }

  var global = tinymce.util.Tools.resolve('tinymce.Env')

  var open = function(editor, currentSearchState) {
    var dialogApi = value()
    editor.undoManager.add()
    var selectedText = global$2.trim(editor.selection.getContent({ format: 'text' }))
    var updateButtonStates = function(api) {
      var updateNext = hasNext(editor, currentSearchState) ? api.enable : api.disable
      updateNext('next')
      var updatePrev = hasPrev(editor, currentSearchState) ? api.enable : api.disable
      updatePrev('prev')
    }
    var updateSearchState = function(api) {
      var data = api.getData()
      var current = currentSearchState.get()
      currentSearchState.set(__assign(__assign({}, current), {
        matchCase: data.matchcase,
        wholeWord: data.wholewords,
        inSelection: data.inselection
      }))
    }
    var disableAll = function(api, disable) {
      var buttons = [
        'replace',
        'replaceall',
        'prev',
        'next'
      ]
      var toggle = disable ? api.disable : api.enable
      each(buttons, toggle)
    }
    var notFoundAlert = function(api) {
      editor.windowManager.alert('Could not find the specified string.', function() {
        api.focus('findtext')
      })
    }
    var focusButtonIfRequired = function(api, name) {
      if (global.browser.isSafari() && global.deviceType.isTouch() && (name === 'find' || name === 'replace' || name === 'replaceall')) {
        api.focus(name)
      }
    }
    var reset = function(api) {
      done(editor, currentSearchState, false)
      disableAll(api, true)
      updateButtonStates(api)
    }
    var doFind = function(api) {
      var data = api.getData()
      var last = currentSearchState.get()
      if (!data.findtext.length) {
        reset(api)
        return
      }
      if (last.text === data.findtext && last.matchCase === data.matchcase && last.wholeWord === data.wholewords) {
        next(editor, currentSearchState)
      } else {
        var count = find(editor, currentSearchState, data.findtext, data.matchcase, data.wholewords, data.inselection)
        if (count <= 0) {
          notFoundAlert(api)
        }
        disableAll(api, count === 0)
      }
      updateButtonStates(api)
    }
    var initialState = currentSearchState.get()
    var initialData = {
      findtext: selectedText,
      replacetext: '',
      wholewords: initialState.wholeWord,
      matchcase: initialState.matchCase,
      inselection: initialState.inSelection
    }
    var spec = {
      title: 'Find and Replace',
      size: 'normal',
      body: {
        type: 'panel',
        items: [
          {
            type: 'bar',
            items: [
              {
                type: 'input',
                name: 'findtext',
                placeholder: 'Find',
                maximized: true,
                inputMode: 'search'
              },
              {
                type: 'button',
                name: 'prev',
                text: 'Previous',
                icon: 'action-prev',
                disabled: true,
                borderless: true
              },
              {
                type: 'button',
                name: 'next',
                text: 'Next',
                icon: 'action-next',
                disabled: true,
                borderless: true
              }
            ]
          },
          {
            type: 'input',
            name: 'replacetext',
            placeholder: 'Replace with',
            inputMode: 'search'
          }
        ]
      },
      buttons: [
        {
          type: 'menu',
          name: 'options',
          icon: 'preferences',
          tooltip: 'Preferences',
          align: 'start',
          items: [
            {
              type: 'togglemenuitem',
              name: 'matchcase',
              text: 'Match case'
            },
            {
              type: 'togglemenuitem',
              name: 'wholewords',
              text: 'Find whole words only'
            },
            {
              type: 'togglemenuitem',
              name: 'inselection',
              text: 'Find in selection'
            }
          ]
        },
        {
          type: 'custom',
          name: 'find',
          text: 'Find',
          primary: true
        },
        {
          type: 'custom',
          name: 'replace',
          text: 'Replace',
          disabled: true
        },
        {
          type: 'custom',
          name: 'replaceall',
          text: 'Replace all',
          disabled: true
        }
      ],
      initialData: initialData,
      onChange: function(api, details) {
        if (details.name === 'findtext' && currentSearchState.get().count > 0) {
          reset(api)
        }
      },
      onAction: function(api, details) {
        var data = api.getData()
        switch (details.name) {
          case 'find':
            doFind(api)
            break
          case 'replace':
            if (!replace(editor, currentSearchState, data.replacetext)) {
              reset(api)
            } else {
              updateButtonStates(api)
            }
            break
          case 'replaceall':
            replace(editor, currentSearchState, data.replacetext, true, true)
            reset(api)
            break
          case 'prev':
            prev(editor, currentSearchState)
            updateButtonStates(api)
            break
          case 'next':
            next(editor, currentSearchState)
            updateButtonStates(api)
            break
          case 'matchcase':
          case 'wholewords':
          case 'inselection':
            updateSearchState(api)
            reset(api)
            break
        }
        focusButtonIfRequired(api, details.name)
      },
      onSubmit: function(api) {
        doFind(api)
        focusButtonIfRequired(api, 'find')
      },
      onClose: function() {
        editor.focus()
        done(editor, currentSearchState)
        editor.undoManager.add()
      }
    }
    dialogApi.set(editor.windowManager.open(spec, { inline: 'toolbar' }))
  }

  var register$1 = function(editor, currentSearchState) {
    editor.addCommand('SearchReplace', function() {
      open(editor, currentSearchState)
    })
  }

  var showDialog = function(editor, currentSearchState) {
    return function() {
      open(editor, currentSearchState)
    }
  }
  var register = function(editor, currentSearchState) {
    editor.ui.registry.addMenuItem('searchreplace', {
      text: 'Find and replace...',
      shortcut: 'Meta+F',
      onAction: showDialog(editor, currentSearchState),
      icon: 'search'
    })
    editor.ui.registry.addButton('searchreplace', {
      tooltip: 'Find and replace',
      onAction: showDialog(editor, currentSearchState),
      icon: 'search'
    })
    editor.shortcuts.add('Meta+F', '', showDialog(editor, currentSearchState))
  }

  function Plugin() {
    global$3.add('searchreplace', function(editor) {
      var currentSearchState = Cell({
        index: -1,
        count: 0,
        text: '',
        matchCase: false,
        wholeWord: false,
        inSelection: false
      })
      register$1(editor, currentSearchState)
      register(editor, currentSearchState)
      return get(editor, currentSearchState)
    })
  }

  Plugin()
}())
